import logging
import json

from manager.autocad_manager import AutoCADManager, CADExecutionError
from features.educational_assistant import EducationalAssistant
from features.optimization_advisor import OptimizationAdvisor
from knowledge_base.gb_standards import GBStandardChecker
from utilities.command_parser import CommandParser


class CadController:
    def __init__(self, ai):
        # 设计上下文跟踪
        self.design_context = {
            "current_layer": "轮廓线",
            "last_entities": [],
            "material": "Q235"
        }
        self.logger = logging.getLogger("CadController")
        self.ai = ai
        self.standards = GBStandardChecker()
        self.edu_helper = EducationalAssistant(self.ai, self.standards)
        self.optimizer = OptimizationAdvisor(self.ai, self.standards)
        self.cad_manager = AutoCADManager()

    def _init_cad_engine(self):
        """初始化CAD引擎"""
        try:
            self.cad = AutoCADManager()
            self.logger.info("AutoCAD连接成功！当前文档：%s", self.cad.acad.doc.Name)
        except Exception as e:
            self.logger.critical("CAD引擎初始化失败：%s", str(e))
            raise RuntimeError("无法启动CAD引擎") from e

    def _package_prompt(self, description):
        return \
            f"""
            根据以下描述生成CAD命令（JSON格式）：
            描述：{description}
            当前图层：{self.design_context['current_layer']}
            材料：{self.design_context['material']}

            要求：
            1. 使用GB/T 14665-2023标准
            2. 包含尺寸公差信息
            3. 支持生成 'circle', 'rectangle', 'gear', 'bolt' 类型的图形
            4. 包含 'command_type' 属性，取值为 'draw', 'modify', 'analyze' 之一
            5. 对于 'rectangle' 类型的图形，必须包含 'start'（起始点，格式为 [x, y]）、'width'（宽度，非负数字）和 'height'（高度，非负数字）字段。
            6. 对于 'circle' 类型的图形，必须包含 'center'（圆心，格式为 [x, y]）和 'radius'（半径，非负数字）字段。
            7. 对于 'gear' 类型的图形，必须包含 'diameter'（直径，非负数字）字段。
            8. 对于 'bolt' 类型的图形，必须包含 'size'（尺寸，非负数字）字段。
            9. 输出格式示例：
            {{
                "command_type": "draw",
                "command": "CIRCLE",
                "entities": [
                 {{
                        "type": "circle",
                        "center": [0, 0],
                        "radius": 50,
                        "layer": "轮廓线"
                 }},
                 {{
                        "type": "rectangle",
                        "start": [10, 10],
                        "width": 20,
                        "height": 30,
                        "layer": "轮廓线"
                    }},
                 {{
                        "type": "gear",
                        "diameter": 20,
                        "layer": "轮廓线"
                    }},
                 {{
                        "type": "bolt",
                        "size": 10,
                        "layer": "轮廓线"
                    }}
                ],
                "compliance": ["GB/T 14665-2023 5.2.1"]
            }}
            注意：'start', 'width', 'height', 'center', 'radius', 'diameter', 'size' 字段对于生成有效的CAD命令至关重要，请确保在输出中包含这些字段。
            """

    @staticmethod
    def _check_entities(entities):
        # 验证 entities 结构
        if entities is None or not isinstance(entities, list):
            raise ValueError("命令中的 'entities' 字段不是有效的列表对象")
        for entity in entities:
            if not isinstance(entity, dict):
                raise ValueError("'entities' 列表中的元素不是有效的字典对象")
            entity_type = entity.get("type")
            if entity_type not in ["circle", "rectangle", "gear", "bolt"]:
                raise ValueError(f"不支持的实体类型: {entity_type}")
            if entity_type == "circle":
                if "center" not in entity or "radius" not in entity:
                    raise ValueError("圆形实体缺少 'center' 或 'radius' 字段")
            elif entity_type == "rectangle":
                if "start" not in entity or "width" not in entity or "height" not in entity:
                    raise ValueError("矩形实体缺少 'start', 'width' 或 'height' 字段")
            elif entity_type == "gear":
                if "diameter" not in entity:
                    raise ValueError("齿轮实体缺少 'diameter' 字段")
            elif entity_type == "bolt":
                if "size" not in entity:
                    raise ValueError("螺栓实体缺少 'size' 字段")

    def ai_draw(self, description):
        """处理绘图指令"""
        prompt = self._package_prompt(description)
        response = self.ai.generate(prompt)
        self.logger.debug("原始响应：%s", response)

        # 解析并验证命令
        command_str = CommandParser.preprocess_response(response)
        try:
            command = json.loads(command_str)  # 解析 JSON 字符串
        except json.JSONDecodeError:
            raise ValueError("无法解析JSON响应")

        if not isinstance(command, dict):
            raise ValueError("解析后的命令不是一个有效的字典对象")

        # 处理可能缺失的 command_type 属性
        if 'command_type' not in command:
            command['command_type'] = 'draw'  # 默认值

        entities = command.get('entities', [])
        self._check_entities(entities)

        # 调用 execute_command 方法时传入解析后的字典
        self.cad.execute_command(command)

        self.design_context['last_entities'] = entities

        return command_str

    def execute_command(self, command):
        self.cad.execute_command(command)

    def handle_drawing(self, description):
        comment = self.ai_draw(description)
        self._feedback(comment)

    def _feedback(self, command_str):
        # 交互反馈
        feedback_prompt = f"对以下CAD草图命令给出建议：{command_str}"
        feedback = self.ai.generate(feedback_prompt)
        print("AI给出的建议：")
        print(feedback)

    def _handle_cad_error(self, error: CADExecutionError, command: str):
        """处理CAD执行错误"""
        print(f"CAD执行错误：{error.user_message}")

        # 自动修复尝试
        try:
            fix_prompt = f"""修复以下CAD命令：
            错误命令：{command}
            错误信息：{error.technical_details}

            要求：
            1. 保持原有设计意图
            2. 符合{self.design_context['material']}材料特性
            3. 输出修正后的JSON命令"""

            fixed_command = self.ai.generate(fix_prompt)
            self.cad.execute_command(fixed_command)
            print("已自动修复并执行命令")

        except Exception as fix_error:
            print("自动修复失败，请手动调整设计")
            self.logger.error("修复失败：%s", str(fix_error))

    def switch_service(self):
        """手动切换AI服务"""
        current_service = "主服务" if self.ai.failure_count < self.ai.max_failures else "备用服务"
        print(f"\n当前服务：{current_service}")
        print("1. 强制使用主服务\n2. 强制使用备用服务\n3. 恢复自动模式")

        choice = input("请选择模式：").strip()
        if choice == "1":
            self.ai.failure_count = 0
            print("已切换至主服务")
        elif choice == "2":
            self.ai.failure_count = self.ai.max_failures
            print("已切换至备用服务")
        elif choice == "3":
            self.ai.failure_count = 0
            print("已恢复自动故障转移模式")

    def perform_checks(self):
        """执行标准检查"""
        violations = self.standards.check_current_design(self.cad)
        if violations:
            print("发现合规问题：")
            for idx, item in enumerate(violations, 1):
                print(f"{idx}. [{item['severity']}] {item['description']}")
                print(f"   标准条款：{item['standard']}")
        else:
            print("设计完全符合当前标准")

    def auto_dimension(self):
        """智能标注"""
        prompt = "为当前设计生成符合GB/T 4458的智能标注方案"
        response = self.ai.generate(prompt)
        try:
            dimensions = json.loads(response)
            self.add_dimensions(dimensions)
            print("已自动添加标注")
        except Exception as e:
            self.logger.error("标注生成失败：%s", str(e))
            raise ValueError("自动标注失败，请手动调整")

    def set_material(self, material: str):
        """设置材料"""
        if material in self.standards.materials:
            self.design_context['material'] = material
            print(f"当前材料已设置为：{material}")
        else:
            raise ValueError(f"不支持的材料：{material}，可用材料：{', '.join(self.standards.materials)}")

    def get_help(self, question: str):
        """获取工程帮助"""
        response = self.edu_helper.explain_standard(question)
        print("\n知识库反馈：")
        print(response)

    def optimize_design(self):
        """优化设计"""
        analysis = self.optimizer.analyze(self.design_context)
        print("\n优化建议：")
        print(analysis.get('summary', '无优化建议'))

        if 'commands' in analysis:
            choice = input("是否应用优化方案？(y/n): ").lower()
            if choice == 'y':
                self.execute_commands(analysis['commands'])
                print("已应用优化方案")

    def create_3d_model(self):
        """根据打开的DWG文件创建三维模型"""
        try:
            # 自动识别并导入打开的DWG文件
            dwg_file = self.cad_manager.get_open_dwg_file()
            if not dwg_file:
                self.logger.warning("未找到打开的DWG文件。")
                return

            # 调起Inventor
            if self.inventor_manager.start_inventor():
                self.inventor_manager.import_dwg_file(dwg_file)
                self.logger.info("成功导入DWG文件并调起Inventor进行三维建模。")
        except Exception as e:
            self.logger.error("创建三维模型时出错：%s", str(e))